package com.vpen.controller;


import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 * @version: 1.0
 * @author: Vpen
 * @date: 2021/9/25 21:00
 * @content:
 */

@Slf4j
@Api(tags = "redis接口")
@RestController
@RequestMapping(value = "${api.prefix.url}/api/redis")
@AllArgsConstructor(onConstructor_ = @Autowired)
public class RedisController {

    private final RedisTemplate<String, Object> redisTemplate;

    private final RedissonClient redissonClient;

    @PostMapping
    @ApiOperation("设置缓存")
    public Object set(@RequestParam("key") String key,
                      @RequestParam("value") String value) {
        redisTemplate.opsForValue().set(key, value);
        return redisTemplate.opsForValue().get(key);
    }

    @PostMapping("/set")
    @ApiOperation("设置多个缓存")
    public Set<Object> setSet(@RequestParam("key") String key,
                              @RequestParam("value") Object... value) {
        redisTemplate.opsForSet().add(key, value);
        return redisTemplate.opsForSet().members(key);
    }

    @PostMapping("/set2")
    @ApiOperation("设缓存")
    public Set<Object> setSet2( ReqSet reqSet) {
        redisTemplate.opsForSet().add(reqSet.getKey(), reqSet.getValue());
        return redisTemplate.opsForSet().members(reqSet.getKey());
    }

    @GetMapping
    @ApiOperation("获取缓存")
    public Object get(@RequestParam("key") String key) {
        return redisTemplate.opsForValue().get(key);
    }

    @DeleteMapping
    @ApiOperation("删除缓存")
    public String delete(@RequestParam("key") String key) {
        Boolean result = redisTemplate.delete(key);
        return result ? "删除成功" : "删除失败";
    }


    @Data
    @Accessors(chain = true)
    public static class ReqSet {
        private String key;
        private Set<String> value;
    }


    /**
     * 没有锁，存在并发问题
     *
     * @param key key
     * @return java.lang.Object
     * @author 韦鹏
     * @date 2021/9/26 23:56
     * @name getPc0
     **/
    @PostMapping("/redisson/nolock")
    @ApiOperation("获取缓存-无锁")
    public Object getPc0(@RequestParam("key") String key) {
        return getValue(key);
    }

    /**
     * 使用setnx，最简单的分布式锁，存在问题，宕机啥的
     *
     * @param key key
     * @return java.lang.Object
     * @author 韦鹏
     * @date 2021/9/26 23:57
     * @name getPc
     **/
    @PostMapping("/redisson")
    @ApiOperation("setnx简单锁")
    public Object getPc(@RequestParam("key") String key) {

        String lock = "lock";
        // setnx  不存在设置，存在返回false
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(lock, "v");

        try {
            if (ifAbsent) {
                return getValue(key);
            }
        } finally {
            // 解锁,删除锁
            redisTemplate.delete(lock);
        }
        return null;
    }


    /**
     * 使用单机分布式锁
     *
     * @param key key
     * @return java.lang.Object
     * @author 韦鹏
     * @date 2021/9/26 23:57
     * @name getPc2
     **/
    @PostMapping("/redisson/lock")
    @ApiOperation("单机分布锁")
    public Object getPc2(@RequestParam("key") String key) {

        String lock = "lock";
        // 设置锁定资源名称
        RLock rlock = redissonClient.getLock(lock);
        boolean isLock;
        try {
            //尝试获取分布式锁----等待 最多0.5秒 15秒后自动释放     1秒=1000毫秒=1000000微秒 milliseconds--毫秒
            isLock = rlock.tryLock(500, 15000, TimeUnit.MILLISECONDS);
            if (isLock) {
                return "hello lock";
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        } finally {
            // 是否有锁
            if (rlock.isLocked()) {
                // 是否是加锁的线程要解锁
                if (rlock.isHeldByCurrentThread()) {
                    // 解锁
                    rlock.unlock();
                }
            }
        }
        return null;

    }


    @GetMapping("/test")
    @ApiOperation("设置锁")
    public String test(){
        String lock ="test:lock";
        RLock rLock = redissonClient.getLock(lock);
       try{
           // MilliSecond 毫秒  最多等待1000毫秒，15秒后自动释放
           if (rLock.tryLock(1000,15000, TimeUnit.MILLISECONDS)) {

               // do something
               System.out.println("hello Lock");

           }
       }catch(InterruptedException e){
           e.printStackTrace();
       }finally {
           if (rLock.isLocked() && rLock.isHeldByCurrentThread() ) {
               rLock.unlock();
           }
       }
        return null;

    }


    public Object getValue(String key) {
        Boolean hasKey = redisTemplate.hasKey(key);
        if (!hasKey) {
            redisTemplate.opsForValue().set(key, "从Redis获取---->所有省市", 10, TimeUnit.SECONDS);
            log.info("从数据库获取......");
            return "从数据库获取---->所有省市";
        } else {
            log.info("有数据，从redis获取....");
            return redisTemplate.opsForValue().get(key);
        }
    }


}
